package com.xxg.renrensearch.init;

import com.xxg.renrensearch.cache.ResourceCache;
import com.xxg.renrensearch.dao.*;
import com.xxg.renrensearch.es.RenRenShopEs;
import com.xxg.renrensearch.repository.RenrenShopShopRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 店铺数据初始化操作
 *
 * @author xuxiaogang
 * @date 2021-11-19
 */
@Component
public class RenrenShopShopInit {
    private final Logger logger = LoggerFactory.getLogger(RenrenShopShopInit.class);
    private final ResourceCache resourceCache;
    private final RenRenShopEs renRenShopEs;
    private final RenrenShopShopRepository renrenShopShopRepository;
    private final RenrenShopShopDao renrenShopShopDao;
    private final RenrenShopShopProfileDao renrenShopShopProfileDao;
    private final static int PAGE_SIZE = 1000;
    private Map<Integer, RenrenShopShop> shopInfoMap;
    private Date syncDate;

    public RenrenShopShopInit(ResourceCache resourceCache, RenRenShopEs renRenShopEs,
                              RenrenShopShopRepository renrenShopShopRepository, RenrenShopShopDao renrenShopShopDao,
                              RenrenShopShopProfileDao renrenShopShopProfileDao) {
        this.resourceCache = resourceCache;
        this.renRenShopEs = renRenShopEs;
        this.renrenShopShopRepository = renrenShopShopRepository;
        this.renrenShopShopDao = renrenShopShopDao;
        this.renrenShopShopProfileDao = renrenShopShopProfileDao;
        syncData();
    }

    /**
     * 同步店铺数据
     */
    public void syncData() {
        logger.info("syncData start");
        syncDate = new Date();
        // 查询索引库中最大的店铺ID和店铺数量
        Integer[] integers = renRenShopEs.getMaxIdCount(RenrenShopShop.class, "id");
        int count = integers[0];
        int maxIndexId = integers[1];
        // 查询数据库中最大的店铺ID
        int maxShopDbId = renrenShopShopDao.getMaxId();
        shopInfoMap = new HashMap<>(maxShopDbId * 4 / 3 + 1);
        int startId, endId, pages;
        if (count > 0) {
            // 索引库有数据，确定分析范围
            pages = (maxIndexId % PAGE_SIZE == 0) ? (maxIndexId / PAGE_SIZE) : (maxIndexId / PAGE_SIZE + 1);
            // 非最后一页
            for (int i = 0; i < pages - 1; i++) {
                startId = i * PAGE_SIZE + 1;
                endId = (i + 1) * PAGE_SIZE;
                analysisDeleteUpdate(startId, endId);
            }
            // 最后一页
            startId = (pages - 1) * PAGE_SIZE + 1;
            endId = maxIndexId;
            analysisDeleteUpdate(startId, endId);
        }
        if (maxShopDbId > maxIndexId) {
            // 查询新增数据集
            int newDataCount = maxShopDbId - maxIndexId;
            pages = (newDataCount % PAGE_SIZE == 0) ? (newDataCount / PAGE_SIZE) : (newDataCount / PAGE_SIZE + 1);
            // 非最后一页
            for (int i = 0; i < pages - 1; i++) {
                startId = i * PAGE_SIZE + maxIndexId + 1;
                endId = (i + 1) * PAGE_SIZE + maxIndexId;
                analysisNew(startId, endId);
            }
            // 最后一页
            startId = (pages - 1) * PAGE_SIZE + maxIndexId + 1;
            endId = maxShopDbId;
            analysisNew(startId, endId);
        }
        logger.info("syncData end");
    }

    /**
     * 分析出删除集合和变更集合
     *
     * @param startId 开始ID
     * @param endId   结束ID
     */
    private void analysisDeleteUpdate(int startId, int endId) {
        logger.info("analysisDeleteUpdate range[" + startId + "," + endId + "]");
        // 定义删除集合
        List<Integer> dList = new LinkedList<>();
        // 定义更新集合
        List<RenrenShopShop> uList = new LinkedList<>();
        List<RenrenShopShop> renrenShopShops = renrenShopShopDao.selectByIdRange(startId, endId);
        // 查询店铺档案
        Map<Integer, RenrenShopShopProfile> shopProfileMap = getShopProfile(startId, endId);
        renrenShopShops.forEach(e -> {
            shopInfoMap.put(e.getId(), e);
            if (e.getIsDeleted()) {
                // 提取删除的店铺
                dList.add(e.getId());
            } else {
                // 提取变更的店铺
                e.setIsDeleted(null);
                if (shopProfileMap.containsKey(e.getId())) {
                    e.setCityText(shopProfileMap.get(e.getId()).getCityText());
                    e.setCityCode(resourceCache.getCityMap().get(e.getCityText()));
                }
                uList.add(e);
            }
        });
        // 删除索引
        deleteIndex(dList);
        // 更新索引
        updateIndex(uList);
    }

    /**
     * 查询出新增集合
     *
     * @param startId 开始ID
     * @param endId   结束ID
     */
    private void analysisNew(int startId, int endId) {
        logger.info("analysisNew range[" + startId + "," + endId + "]");
        // 定义新增集合
        List<RenrenShopShop> aList = new ArrayList<>();
        List<RenrenShopShop> renrenShopShops = renrenShopShopDao.selectByIdRange(startId, endId);
        // 查询店铺档案
        Map<Integer, RenrenShopShopProfile> shopProfileMap = getShopProfile(startId, endId);
        renrenShopShops.forEach(e -> {
            shopInfoMap.put(e.getId(), e);
            if (!e.getIsDeleted()) {
                if (shopProfileMap.containsKey(e.getId())) {
                    e.setCityText(shopProfileMap.get(e.getId()).getCityText());
                    e.setCityCode(resourceCache.getCityMap().get(e.getCityText()));
                }
                aList.add(e);
            }
        });
        // 添加索引
        addIndex(aList);
    }

    /**
     * 获取所有店铺档案信息
     */
    private Map<Integer, RenrenShopShopProfile> getShopProfile(int startId, int endId) {
        List<RenrenShopShopProfile> shopProfiles = renrenShopShopProfileDao.selectByShopIdRange(startId, endId);
        return shopProfiles.stream().collect(Collectors.toMap(RenrenShopShopProfile::getShopId, e -> e));
    }

    /**
     * 新增索引
     *
     * @param shops 新的店铺
     */
    private void addIndex(List<RenrenShopShop> shops) {
        renrenShopShopRepository.saveAll(shops);
    }

    /**
     * 更新索引
     *
     * @param shops 变更的店铺
     */
    private void updateIndex(List<RenrenShopShop> shops) {
        renRenShopEs.updateShopIndex(shops);
    }

    /**
     * 删除索引
     *
     * @param ids 删除的店铺Id列表
     */
    private void deleteIndex(List<Integer> ids) {
        renrenShopShopRepository.deleteAllById(ids);
    }

    /**
     * 查询店铺信息表
     *
     * @return 结果
     */
    public Map<Integer, RenrenShopShop> getShopInfoMap() {
        return shopInfoMap;
    }

    /**
     * 获取同步的时间戳
     *
     * @return 时间戳
     */
    public String getSyncDateStr() {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return simpleDateFormat.format(syncDate);
    }
}
